import { Actor, ActorSystem, Props, Context, PID } from '../src';
import { 
  PersistentActor, 
  EventType, 
  RecoverContext, 
  CommandContext,
  InMemoryProvider,
  FileSystemProvider,
  PersistenceFactory
} from '../src/persistence';

// Import RecoveryStrategy directly from persistenceFactory.ts
import { RecoveryStrategy } from '../src/persistence/persistenceFactory';

/**
 * 计数器命令类型
 */
enum CounterCommandType {
  Increment = 'increment',
  Decrement = 'decrement',
  GetCount = 'get-count',
  Reset = 'reset',
  CreateSnapshot = 'create-snapshot'
}

/**
 * 计数器事件类型
 */
enum CounterEventType {
  Incremented = 'incremented',
  Decremented = 'decremented',
  Reset = 'reset'
}

/**
 * 计数器命令
 */
interface CounterCommand {
  type: CounterCommandType;
  amount?: number;
}

/**
 * 计数器事件
 */
interface CounterEvent {
  type: CounterEventType;
  amount?: number;
}

/**
 * 计数器状态
 */
interface CounterState {
  count: number;
}

/**
 * 持久化计数器 Actor
 */
class PersistentCounterActor extends PersistentActor {
  // 持久化 ID
  private _persistenceId: string;
  
  // 当前计数
  private count: number = 0;
  
  // 事件索引
  private eventIndex: number = 0;
  
  // 上次快照索引
  private lastSnapshotIndex: number = 0;
  
  // 快照间隔
  private readonly snapshotInterval: number = 10;
  
  /**
   * 构造函数
   * @param id 计数器 ID
   */
  constructor(id: string) {
    super();
    this._persistenceId = `counter-${id}`;
  }
  
  /**
   * 获取持久化 ID
   */
  get persistenceId(): string {
    return this._persistenceId;
  }
  
  /**
   * 恢复事件处理
   * @param context 恢复上下文
   */
  receiveRecover(context: RecoverContext): void {
    const event = context.event;
    
    // 处理不同类型的恢复事件
    if (context.eventType === EventType.Snapshot) {
      // 从快照恢复状态
      console.log(`[${this.persistenceId}] Recovering from snapshot:`, event);
      const state = event as CounterState;
      this.count = state.count;
      this.lastSnapshotIndex = context.eventIndex;
    } else {
      // 从事件恢复状态
      const counterEvent = event as CounterEvent;
      console.log(`[${this.persistenceId}] Recovering from event:`, counterEvent);
      
      this.applyEvent(counterEvent);
      this.eventIndex = context.eventIndex;
    }
  }
  
  /**
   * 命令处理
   * @param context 命令上下文
   */
  receiveCommand(context: CommandContext): void {
    const message = context.message() as CounterCommand;
    
    switch (message.type) {
      case CounterCommandType.Increment:
        // 增加计数
        const incrementAmount = message.amount || 1;
        const incrementEvent: CounterEvent = { 
          type: CounterEventType.Incremented, 
          amount: incrementAmount 
        };
        
        // 持久化事件
        this.persist(incrementEvent).then(() => {
          this.eventIndex++;
          this.applyEvent(incrementEvent);
          context.respond({ count: this.count });
          
          // 检查是否需要创建快照
          this.checkSnapshot(context);
        });
        break;
        
      case CounterCommandType.Decrement:
        // 减少计数
        const decrementAmount = message.amount || 1;
        const decrementEvent: CounterEvent = { 
          type: CounterEventType.Decremented, 
          amount: decrementAmount 
        };
        
        // 持久化事件
        this.persist(decrementEvent).then(() => {
          this.eventIndex++;
          this.applyEvent(decrementEvent);
          context.respond({ count: this.count });
          
          // 检查是否需要创建快照
          this.checkSnapshot(context);
        });
        break;
        
      case CounterCommandType.Reset:
        // 重置计数
        const resetEvent: CounterEvent = { type: CounterEventType.Reset };
        
        // 持久化事件
        this.persist(resetEvent).then(() => {
          this.eventIndex++;
          this.applyEvent(resetEvent);
          context.respond({ count: this.count });
          
          // 重置后总是创建快照
          this.takeSnapshot(context);
        });
        break;
        
      case CounterCommandType.GetCount:
        // 获取当前计数 (只读操作，不需要持久化)
        context.respond({ count: this.count });
        break;
        
      case CounterCommandType.CreateSnapshot:
        // 手动创建快照
        this.takeSnapshot(context);
        context.respond({ count: this.count, snapshotCreated: true });
        break;
        
      default:
        console.warn(`[${this.persistenceId}] Unknown command:`, message);
        break;
    }
  }
  
  /**
   * 应用事件到状态
   * @param event 事件
   */
  private applyEvent(event: CounterEvent): void {
    switch (event.type) {
      case CounterEventType.Incremented:
        this.count += event.amount || 1;
        break;
        
      case CounterEventType.Decremented:
        this.count -= event.amount || 1;
        break;
        
      case CounterEventType.Reset:
        this.count = 0;
        break;
    }
  }
  
  /**
   * 检查是否需要创建快照
   * @param context 命令上下文
   */
  private checkSnapshot(context: CommandContext): void {
    // 当事件数达到快照间隔时创建快照
    if (this.eventIndex - this.lastSnapshotIndex >= this.snapshotInterval) {
      this.takeSnapshot(context);
    }
  }
  
  /**
   * 创建状态快照
   * @param context 命令上下文
   */
  private takeSnapshot(context: CommandContext): void {
    const state: CounterState = { count: this.count };
    this.createSnapshot(state).then(() => {
      console.log(`[${this.persistenceId}] Created snapshot:`, state);
      this.lastSnapshotIndex = this.eventIndex;
    }).catch(error => {
      console.error(`[${this.persistenceId}] Failed to create snapshot:`, error);
    });
  }
  
  /**
   * 恢复完成处理
   * @param context 上下文
   */
  protected onRecoveryCompleted(context: any): void {
    console.log(`[${this.persistenceId}] Recovery completed, current count: ${this.count}`);
  }
}

/**
 * 运行内存持久化示例
 */
async function runInMemoryExample() {
  console.log('========================================');
  console.log('| 内存持久化计数器示例                |');
  console.log('========================================');
  
  // 创建 Actor 系统
  const system = new ActorSystem();
  
  // 创建持久化工厂
  const factory = PersistenceFactory.getInstance();
  
  // 注册内存持久化提供者
  const provider = factory.createInMemoryProvider('memory');
  
  // 创建持久化 Actor 的 Props
  const props = factory.persistentProps(
    () => new PersistentCounterActor('memory'),
    'memory',
    {
      recoveryStrategy: RecoveryStrategy.SnapshotThenEvents,
      snapshotInterval: 10
    }
  );
  
  // 创建 Actor
  const pid = system.root.spawn(props);
  
  try {
    // 执行一系列操作
    console.log('初始化计数器...');
    
    // 增加计数器
    for (let i = 1; i <= 5; i++) {
      const result = await system.root.requestFuture(pid, { type: CounterCommandType.Increment }, 1000);
      console.log(`增加操作 #${i}, 当前计数:`, result['count']);
    }
    
    // 获取当前状态
    const getResult1 = await system.root.requestFuture(pid, { type: CounterCommandType.GetCount }, 1000);
    console.log('当前计数:', getResult1['count']);
    
    // 减少计数器
    const decrementResult = await system.root.requestFuture(
      pid, 
      { type: CounterCommandType.Decrement, amount: 2 }, 
      1000
    );
    console.log('减少 2 后的计数:', decrementResult['count']);
    
    // 手动创建快照
    const snapshotResult = await system.root.requestFuture(
      pid, 
      { type: CounterCommandType.CreateSnapshot }, 
      1000
    );
    console.log('创建快照后的状态:', snapshotResult);
    
    // 重置计数器
    const resetResult = await system.root.requestFuture(pid, { type: CounterCommandType.Reset }, 1000);
    console.log('重置后的计数:', resetResult['count']);
    
    // 再次增加计数器
    const incrementResult = await system.root.requestFuture(
      pid, 
      { type: CounterCommandType.Increment, amount: 10 }, 
      1000
    );
    console.log('增加 10 后的计数:', incrementResult['count']);
    
    // 停止 Actor
    console.log('停止 Actor...');
    system.root.stop(pid);
    
    // 等待一段时间
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // 重新创建 Actor
    console.log('重新创建 Actor，将从持久化存储恢复状态...');
    const newPid = system.root.spawn(props);
    
    // 获取恢复的状态
    const getResult2 = await system.root.requestFuture(newPid, { type: CounterCommandType.GetCount }, 1000);
    console.log('恢复后的计数:', getResult2['count']);
    
    // 执行更多操作
    const finalResult = await system.root.requestFuture(
      newPid, 
      { type: CounterCommandType.Increment, amount: 5 }, 
      1000
    );
    console.log('最终计数:', finalResult['count']);
    
    // 最后停止 Actor
    system.root.stop(newPid);
  } catch (error) {
    console.error('执行过程中出错:', error);
  } finally {
    // 关闭 Actor 系统
    await system.terminate();
  }
}

/**
 * 运行文件系统持久化示例
 */
async function runFileSystemExample() {
  console.log('\n========================================');
  console.log('| 文件系统持久化计数器示例            |');
  console.log('========================================');
  
  // 创建 Actor 系统
  const system = new ActorSystem();
  
  // 创建持久化工厂
  const factory = PersistenceFactory.getInstance();
  
  // 注册文件系统持久化提供者
  const provider = factory.createFileSystemProvider('./data/persistence', 'file');
  
  // 创建持久化 Actor 的 Props
  const props = factory.persistentProps(
    () => new PersistentCounterActor('file'),
    'file',
    {
      recoveryStrategy: RecoveryStrategy.SnapshotThenEvents,
      snapshotInterval: 5
    }
  );
  
  // 创建 Actor
  const pid = system.root.spawn(props);
  
  try {
    console.log('文件系统持久化计数器初始化...');
    console.log('注意: 数据将保存在 ./data/persistence 目录');
    
    // 获取初始状态 (可能从文件中恢复)
    const initialState = await system.root.requestFuture(pid, { type: CounterCommandType.GetCount }, 1000);
    console.log('初始/恢复的计数:', initialState['count']);
    
    // 执行一系列操作
    for (let i = 1; i <= 8; i++) {
      const result = await system.root.requestFuture(
        pid, 
        { type: CounterCommandType.Increment, amount: i }, 
        1000
      );
      console.log(`增加 ${i} 后的计数:`, result['count']);
    }
    
    // 手动创建快照
    await system.root.requestFuture(pid, { type: CounterCommandType.CreateSnapshot }, 1000);
    console.log('已创建快照');
    
    // 停止 Actor
    console.log('停止 Actor...');
    system.root.stop(pid);
    
    // 等待一段时间
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // 重新创建 Actor
    console.log('重新创建 Actor，将从文件系统恢复状态...');
    const newPid = system.root.spawn(props);
    
    // 获取恢复的状态
    const recoveredState = await system.root.requestFuture(newPid, { type: CounterCommandType.GetCount }, 1000);
    console.log('从文件系统恢复后的计数:', recoveredState['count']);
    
    // 减少计数
    const decrementResult = await system.root.requestFuture(
      newPid, 
      { type: CounterCommandType.Decrement, amount: 5 }, 
      1000
    );
    console.log('减少 5 后的计数:', decrementResult['count']);
    
    // 最后停止 Actor
    system.root.stop(newPid);
  } catch (error) {
    console.error('执行过程中出错:', error);
  } finally {
    // 关闭 Actor 系统
    await system.terminate();
  }
  
  console.log('文件系统持久化示例完成。您可以重新运行此示例，之前的状态将会被恢复。');
}

/**
 * 运行示例
 */
async function runExample() {
  try {
    // 运行内存持久化示例
    await runInMemoryExample();
    
    // 运行文件系统持久化示例
    await runFileSystemExample();
    
    console.log('\n所有示例已完成');
  } catch (error) {
    console.error('示例运行失败:', error);
  }
}

// 执行示例
runExample().catch(console.error); 